package com.ccp.dev.system.service;

import com.ccp.dev.core.basic.base.BaseService;
import com.ccp.dev.core.basic.util.UUIDUtils;
import com.ccp.dev.core.util.StringUtil;
import com.ccp.dev.system.configuration.CustomPwdEncoder;
import com.ccp.dev.system.dao.PwdStrategyDao;
import com.ccp.dev.system.model.PwdStrategy;
import com.ccp.dev.system.model.SysUser;
import net.sf.json.JSONObject;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * sys_pwd_strategy Service类
 * @author y
 */
@Service
public class PwdStrategyService extends BaseService<PwdStrategy> {
	@Resource
	private PwdStrategyDao dao;

	/**
	 * 更新状态
	 * @param id  主键
	 * @param enable 是否启用状态
	 */
	public void updateEnable(String id, Short enable) {
		Map<String, Object> map = new HashMap<String, Object>();
		//1:如果是启动，先把所有设置为0(false)，只能有一个策略生效
		closeAll();

		//2:设置为enable 可以是启动或关闭
		map.put("id", id);
		map.put("enable", enable);
		dao.updateEnable(map);
	}

	public void closeAll() {
		Map<String, Object> map = new HashMap<String, Object>();
		//1:如果是启动，先把所有设置为0(false)，只能有一个策略生效
		map.put("enable", PwdStrategy.ENABLE_NO);
		dao.updateEnable(map);
	}

	/**
	 * 保存 sys_pwd_strategy 信息
	 * @param pwdStrategy 策略model
	 */
	public void save(PwdStrategy pwdStrategy) {
		String id = pwdStrategy.getId();
		//启动，那么就先关闭所有
		if (PwdStrategy.ENABLE_YES.equals(pwdStrategy.getEnable()) ) {
			closeAll();
		}

		// 当密码过期不处理时，强制过期时间为0
		if (pwdStrategy.getHandleOverdue() == 0){
			pwdStrategy.setValidity((short)0);
		}
		if (StringUtil.isEmpty(id)) {
			id = UUIDUtils.getUUIDFor32();
			pwdStrategy.setId(id);
			this.add(pwdStrategy);
		} else {
			this.update(pwdStrategy);
		}
	}

	/**
	 * 获取系统中生效的密码策略
	 * @return PwdStrategy
	 */
	public PwdStrategy getUsing() {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("enable", PwdStrategy.ENABLE_YES);
		return dao.getByEnable(map);
	}

	/**
	 * 检查密码策略
	 * @param newPassword  新密码
	 * @throws Exception 异常
	 */
	public void checkStrategy(String newPassword) throws Exception{
		PwdStrategy usePwdStrategy = getUsing();
		if(null != usePwdStrategy){
			JSONObject jsonObject = checkUser(null,newPassword);
			int status = jsonObject.getInt("status");
			if(PwdStrategy.Status.SUCCESS != status){
				if(PwdStrategy.Status.LENGTH_TOO_SHORT == status){
					//特殊处理提示信息中变量值
					throw new Exception(jsonObject.getString("msg")+"_"+usePwdStrategy.getPwdLength());
				}else{
					throw new Exception(jsonObject.getString("msg"));
				}
			}
		}else{
			//如果没有密码策略，为了安全等级保护要求，保存用户或修改密码时设置默认密码策略
			if (!newPassword.matches("(?![0-9A-Z]+$)(?![0-9a-z]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{10,18}$")) {
				throw new Exception("pwdStrategy.unSafe.warning");
			}
		}
	}


	/**
	 * 检查系统密码规则
	 * @param user
	 *            :用户
	 * @param pwd
	 *            :没有加密前的密码
	 * @return JSONObject
	 * @since 1.0.0
	 */
	public JSONObject checkUser(SysUser user, String pwd) {
		return checkUser(getUsing(), user, pwd);
	}

	/**
	 * 检查策略
	 * @param pwdStrategy 策略
	 * @param user 用户
	 * @param pwd 明文密码
	 * @return JSONObject
	 */
	private JSONObject checkUser(PwdStrategy pwdStrategy, SysUser user, String pwd) {
		JSONObject result = new JSONObject();
		if(StringUtil.isEmpty(pwd)){
			if(StringUtil.isNotEmpty(pwdStrategy.getInitPwd())){
				CustomPwdEncoder customPwdEncoder = new CustomPwdEncoder();
				String enInitPwd = customPwdEncoder.encode(pwdStrategy.getInitPwd());
				String password = user.getPassword();
				//强制修改初始化密码
				if(enInitPwd.equals(password) && PwdStrategy.FORCE_CHANGE_INIT_PWD_YES.equals(pwdStrategy.getForceChangeInitPwd())){
					result.put("msg", "pwdStrategy.initPwdConsistent.warning");
					result.put("status", PwdStrategy.Status.NEED_TO_CHANGE_PWD);
					return result;
				}
			}
			//过期修改
			if (PwdStrategy.HANDLE_OVERDUE_MODIFY.equals(pwdStrategy.getHandleOverdue())) {
				//密码有效期 默认周期为月（30天）
				if (pwdStrategy.getValidity() > 0) {
					//有效期，换算成毫秒数
					long validity = Long.parseLong(pwdStrategy.getValidity().toString()) * 2592000 * 1000;
					long pwdUpdTime = user.getPwdUpdTime().getTime();
					long now = System.currentTimeMillis();
					//已过了期限
					if (now - pwdUpdTime > validity) {
						result.put("msg", "pwdStrategy.pwdExpired.warning");
						result.put("status", PwdStrategy.Status.PWD_OVERDUE);
						return result;
					}
				}
			}
		}else{
			//检查密码策略
			//非无限制
			if (pwdStrategy.getPwdRule() != 0) {
				//策略是字母跟数字，但是不符合
				if (pwdStrategy.getPwdRule() == 1 && !pwd.matches("^(?!^\\d+$)(?!^[a-zA-Z]+$)[0-9a-zA-Z]{2,}$")) {
					result.put("msg", "pwdStrategy.letterPlusNumber.warning");
					result.put("status", PwdStrategy.Status.NO_MATCH_NUMANDWORD);
					return result;
				}
				//字母跟数字跟特殊字符
				if (pwdStrategy.getPwdRule() == 2) {
					//因为这个正则太难写。。所以分为两步完成验证
					//1 先确保密码有特殊字符
					//是否符合规则
					boolean b = false;
					String regEx = "[`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？]";
					Pattern p = Pattern.compile(regEx);
					Matcher m = p.matcher(pwd);
					if (m.find()) {
						//找到特殊字符
						//删除特殊字符，开始验证数字和字母
						String temp = m.replaceAll("").trim();
						b = temp.matches("^(?!^\\d+$)(?!^[a-zA-Z]+$)[0-9a-zA-Z]{2,}$");
					}
					if (!b) {
						result.put("msg", "pwdStrategy.letterPlusNumberPlusCharacter.warning");
						result.put("status", PwdStrategy.Status.NO_MATCH_NUMANDWORDANDSPECIAL);
						return result;
					}
				}
			}
			int pwdLength = pwdStrategy.getPwdLength();
			//检查密码长度
			if (pwdLength > 0) {
				if (pwd.length() < pwdLength) {
					result.put("msg", "pwdStrategy.pwdShortLength.warning");
					result.put("status",PwdStrategy.Status.LENGTH_TOO_SHORT);
					return result;
				}
			}
		}
		result.put("status", PwdStrategy.Status.SUCCESS);
		result.put("msg", "pwdStrategy.success");
		return result;
	}
}
